Passed
Push — master ( 438240...a8a479 )
by Kevin Van
04:17
created

GamePage   C

Complexity

Total Complexity 54

Size/Duplication

Total Lines 302
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 54
eloc 258
dl 0
loc 302
rs 6.4799
c 0
b 0
f 0

11 Functions

Rating   Name   Duplication   Size   Complexity  
A componentDidMount 0 3 1
A updateData 0 11 2
A renderScore 0 9 2
B renderEventLine 0 68 5
A renderLineupLine 0 17 3
A renderSubLine 0 15 3
A renderLineup 0 8 1
A renderEvents 0 3 1
A renderScoreWithWinnerIndicator 0 5 2
A renderLineupHeader 0 11 1
F render 0 111 33

How to fix   Complexity   

Complexity

Complex classes like GamePage often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import { graphql } from "gatsby"
2
import moment from "moment-timezone"
3
import "moment-timezone/node_modules/moment/locale/nl-be"
4
import React, { Component, Fragment } from "react"
5
import LazyLoad from "react-lazy-load"
6
7
import Icon from "../components/Icon"
8
import MiniRanking from "../components/MiniRanking"
9
import Spinner from "../components/Spinner"
10
import SEO from "../components/seo"
11
import iconBench from "../images/i_bench_2.png"
12
import iconCardRed from "../images/i_card_red.png"
13
import iconCardYellow from "../images/i_card_yellow.png"
14
import iconCardYellowRed from "../images/i_card_yellow_red.png"
15
import iconGoal from "../images/i_goal.png"
16
import iconStart from "../images/i_start.png"
17
import iconSubIn from "../images/i_sub_in.png"
18
import iconSubOut from "../images/i_sub_out.png"
19
import Layout from "../layouts/index"
20
import { mapPsdStatus } from "../scripts/helper"
21
22
class GamePage extends Component {
23
  constructor(props) {
24
    super(props)
25
26
    this.state = {
27
      data: [],
28
      loading: true,
29
    }
30
31
    const {
32
      data: {
33
        site: {
34
          siteMetadata: { kcvvPsdApi },
35
        },
36
      },
37
    } = this.props
38
39
    this.kcvvPsdApi = kcvvPsdApi
40
    this.matchId = this.props.id || null
41
  }
42
43
  updateData() {
44
    if (this.matchId === null) {
45
      return
46
    }
47
48
    const apiUrl = `${this.kcvvPsdApi}/match/${this.matchId}`
49
50
    fetch(apiUrl)
51
      .then((response) => response.json())
52
      .then((json) => this.setState({ data: json, loading: false }))
53
  }
54
55
  componentDidMount() {
56
    this.updateData()
57
  }
58
59
  render() {
60
    if (this.matchId === null) {
61
      return (
62
        <Layout>
63
          <section className="grid-container site-content">Geen match beschikbaar...</section>
64
        </Layout>
65
      )
66
    }
67
68
    moment.tz.setDefault(`Europe/Brussels`)
69
    moment.locale(`nl-be`)
70
    moment.localeData(`nl-be`)
71
72
    if (this.state.loading === false && this.state.data) {
73
      const { general = {}, substitutes = {}, lineup = {}, events = [] } = this.state.data
74
      const homeTeamId = general.homeClub?.id
75
      const ogImage = {
76
        src: general?.homeClub?.logo,
77
        width: 180,
78
        height: 180,
79
      }
80
81
      const { home: homeLineup = [], away: awayLineup = [] } = lineup || {}
82
      const { home: homeSubs = [], away: awaySubs = [] } = substitutes || {}
83
84
      const matchTime = moment(general.date)
85
86
      return (
87
        <Layout>
88
          <SEO
89
            lang="nl-BE"
90
            title={`Matchverslag ${general.homeClub?.abbreviation || general?.homeClub?.name} - ${
91
              general.awayClub?.abbreviation || general?.awayClub?.name
92
            }`}
93
            description={`Matchverslag ${general.homeClub?.abbreviation || general?.homeClub?.name} - ${
94
              general.awayClub?.abbreviation || general?.awayClub?.name
95
            }`}
96
            path={`/game/${general?.id}`}
97
            image={ogImage}
98
          />
99
100
          <section className="grid-container game-stats">
101
            <div className="grid-x grid-margin-x">
102
              <div className={`cell large-12 center game__details`}>
103
                <div className="game__teams">
104
                  <div className={`game__teams-inner`}>
105
                    <LazyLoad debounce={false}>
106
                      <img src={general.homeClub?.logo} alt={general.homeClub?.name} title={general.homeClub?.name} />
107
                    </LazyLoad>
108
                  </div>
109
                  {this.renderScore(general.goalsHomeTeam, general.goalsAwayTeam)}
110
                  <div className={`game__teams-inner`}>
111
                    <LazyLoad debounce={false}>
112
                      <img src={general.awayClub?.logo} alt={general.awayClub?.name} title={general.awayClub?.name} />
113
                    </LazyLoad>
114
                  </div>
115
                </div>
116
                <h1>{`${general.homeClub?.abbreviation || general.homeClub?.name} - ${
117
                  general.awayClub?.abbreviation || general.awayClub?.name
118
                }`}</h1>
119
                <h4>{general.competitionType}</h4>
120
                <time dateTime={matchTime.format(`YYYY-MM-DD - H:mm`)}>
121
                  {matchTime.format(`dddd DD MMMM YYYY - H:mm`)}
122
                </time>
123
                <br />
124
125
                {general.status !== 0 && (
126
                  <span className={`game__status game__status--${general.status}`}>{mapPsdStatus(general.status)}</span>
127
                )}
128
129
                <br />
130
              </div>
131
              {(homeLineup.length !== 0 || awayLineup.length !== 0) && (
132
                <div className={`lineup__wrapper grid-x grid-margin-x cell large-12`}>
133
                  <div className={`cell large-6 lineup__wrapper--home`}>
134
                    <h3>{general.homeClub?.name}</h3>
135
                    {homeLineup && this.renderLineup(homeLineup, homeSubs)}
136
                  </div>
137
                  <div className={`cell large-6 lineup__wrapper--away`}>
138
                    <h3>{general.awayClub?.name}</h3>
139
                    {awayLineup && this.renderLineup(awayLineup, awaySubs)}
140
                  </div>
141
                </div>
142
              )}
143
144
              {events.length !== 0 && (
145
                <div className={`cell large-12 event__wrapper`}>
146
                  <h3>Gebeurtenissen</h3>
147
                  {events && this.renderEvents(events, homeTeamId)}
148
                </div>
149
              )}
150
            </div>
151
          </section>
152
153
          {general.competitionType === `Competitie` && (
154
            <MiniRanking
155
              teamId={general.homeTeamId || general.awayTeamId}
156
              homeTeam={general.homeClub?.name}
157
              awayTeam={general.awayClub?.name}
158
            />
159
          )}
160
        </Layout>
161
      )
162
    } else {
163
      return (
164
        <Layout>
165
          <section className="grid-container site-content">
166
            <Spinner />
167
          </section>
168
        </Layout>
169
      )
170
    }
171
  }
172
173
  renderScore = (resultHome, resultAway) => {
174
    return resultHome !== null && resultAway !== null ? (
175
      <div className={`match-details__vs match-details__vs--score`}>
176
        {this.renderScoreWithWinnerIndicator(resultHome, resultAway, `home`)}
177
        <span className={`match-details__divider`}>&nbsp;-&nbsp;</span>
178
        {this.renderScoreWithWinnerIndicator(resultAway, resultHome, `away`)}
179
      </div>
180
    ) : (
181
      <div className={`match-details__vs`}>VS</div>
182
    )
183
  }
184
185
  renderScoreWithWinnerIndicator = (result1, result2, extraClass) => {
186
    return result1 > result2 ? (
187
      <span className={`match-details__winner match-details__winner--${extraClass}`}>{result1}</span>
188
    ) : (
189
      <span className={`match-details__loser`}>{result1}</span>
190
    )
191
  }
192
193
  renderEvents(events, homeTeamId) {
194
    return <Fragment>{events.map((element, i) => this.renderEventLine(i, element, homeTeamId))}</Fragment>
195
  }
196
197
  renderEventLine(i, element, homeTeamId) {
198
    const homeTeam = element.clubId == homeTeamId
199
    let actionIcon = null
200
    let actionMessage = ``
201
    let actionText = ``
202
203
    switch (element.action) {
204
      case `geel`:
205
        actionIcon = iconCardYellow
206
        actionText = `Gele kaart voor`
207
        actionMessage = `Gele kaart`
208
        break
209
      case `rood`:
210
        actionIcon = iconCardRed
211
        actionText = `Rode kaart voor`
212
        actionMessage = `Rode kaart`
213
        break
214
      case `tweedegeel`:
215
        actionIcon = iconCardYellowRed
216
        actionText = `Tweede gele kaart voor`
217
        actionMessage = `Tweede gele kaart`
218
        break
219
      case `doelpunt`:
220
        actionIcon = iconGoal
221
        actionText = `${element?.goalsHome} - ${element?.goalsAway} — Doelpunt gescoord door`
222
        actionMessage = `Doelpunt`
223
        break
224
      case `minuteOut`:
225
        actionIcon = iconSubOut
226
        actionText = `Speler uit: `
227
        actionMessage = `Wissel`
228
        break
229
      case `minuteIn`:
230
        actionIcon = iconSubIn
231
        actionText = `Speler in: `
232
        actionMessage = `Wissel`
233
        break
234
    }
235
236
    return (
237
      <div className={`event__row ${homeTeam ? `event__row--home` : `event__row--away`} grid-x grid-margin-x`} key={i}>
238
        {homeTeam && (
239
          <span className={`event__row__item event__row__item--home lineup__item--name cell small-10 large-4`}>
240
            {actionText} {element.playerName}
241
          </span>
242
        )}
243
        {homeTeam && (
244
          <span
245
            className={`event__row__item event__row__item--home lineup__item--action cell small-1 center`}
246
            style={{ backgroundImage: `url(${actionIcon})` }}
247
            title={actionMessage}
248
          ></span>
249
        )}
250
        <span className={`event__row__item lineup__item--time cell small-1 large-2 center`}>{element.minute}'</span>
251
        {homeTeam || (
252
          <span
253
            className={`event__row__item event__row__item--away lineup__item--action cell small-1 center`}
254
            style={{ backgroundImage: `url(${actionIcon})` }}
255
            title={actionMessage}
256
          ></span>
257
        )}
258
        {homeTeam || (
259
          <span className={`event__row__item event__row__item--away lineup__item--name cell small-10 large-4`}>
260
            {actionText} {element.playerName}
261
          </span>
262
        )}
263
      </div>
264
    )
265
  }
266
  renderLineup(lineup, substitutes) {
267
    return (
268
      <Fragment>
269
        {this.renderLineupHeader()}
270
        {lineup.map((element, i) => this.renderLineupLine(i, element))}
271
        <hr />
272
        {substitutes.map((element, i) => this.renderSubLine(i, element))}
273
      </Fragment>
274
    )
275
  }
276
277
  renderLineupHeader() {
278
    return (
279
      <div className={`lineup__header grid-x grid-margin-x`}>
280
        <span className={`lineup__header__item lineup__item--status cell small-1`}></span>
281
        <span className={`lineup__header__item lineup__item--number cell small-1`}>#</span>
282
        <span className={`lineup__header__item lineup__item--name cell small-9`}>Name</span>
283
        <span className={`lineup__header__item lineup__item--time cell small-1`}>
284
          <Icon icon="fa-clock-o" />
285
        </span>
286
      </div>
287
    )
288
  }
289
290
  renderSubLine(i, element) {
291
    return (
292
      <div className={`lineup__row lineup__row--substitute grid-x grid-margin-x`} key={i}>
293
        <span
294
          className={`lineup__row__item lineup__item--status cell small-1`}
295
          style={{
296
            backgroundImage: `url(${element.changed ? iconSubIn : iconBench})`,
297
          }}
298
          title={`${element.changed ? `Wisselspeler ingevallen` : `Wisselspeler`}`}
299
        ></span>
300
        <span className={`lineup__row__item lineup__item--number cell small-1`}>{element.number}</span>
301
        <span className={`lineup__row__item lineup__item--name cell small-9`}>{element.playerName}</span>
302
        <span className={`lineup__row__item lineup__item--time cell small-1`}>{element.minutesPlayed}'</span>
303
      </div>
304
    )
305
  }
306
307
  renderLineupLine(i, element) {
308
    return (
309
      <div className={`lineup__row lineup__row--lineup grid-x grid-margin-x`} key={i}>
310
        <span
311
          className={`lineup__row__item lineup__item--status cell small-1`}
312
          style={{
313
            backgroundImage: `url(${element.changed ? iconSubOut : iconStart})`,
314
          }}
315
          title={`${element.changed ? `Basisspeler gewisseld` : `Basisspeler`}`}
316
        ></span>
317
        <span className={`lineup__row__item lineup__item--number cell small-1`}>{element.number}</span>
318
        <span className={`lineup__row__item lineup__item--name cell small-9`}>
319
          {element.playerName} {element.captain && `(C)`}
320
        </span>
321
        <span className={`lineup__row__item lineup__item--time cell small-1`}>{element.minutesPlayed}'</span>
322
      </div>
323
    )
324
  }
325
}
326
327
export const pageQuery = graphql`
328
  query {
329
    site {
330
      siteMetadata {
331
        kcvvPsdApi
332
      }
333
    }
334
  }
335
`
336
337
export default GamePage
338